package os.kernelProcess.schedulers;

import java.util.Enumeration;
import java.util.Hashtable;

import os.MiniProcess;
import os.MiniSemaphore;
import os.MiniThread;
import os.kernelProcess.SchedulerThread;
import os.kernelProcess.queues.FCFSQueue;

public  class FCFSScheduler extends SchedulerThread {

	private MiniSemaphore waiting;

	public FCFSScheduler(MiniProcess process, String tid) {
		super(process, tid);
		readyQueue = new FCFSQueue();
		suspendedQueue = new Hashtable<String, MiniThread>();
		waiting = new MiniSemaphore(0);
	}

	@Override
	public void schedule() {

		while (true) {
			if (readyQueue.getSize() != 0) {
				runningThread = readyQueue.getHead();
				readyQueue.removeThread(runningThread.getTid());
				runningThread.setThreadState(MiniThread.THREAD_RUNNING);
				runningThread.resumeExecution();
			}
			waiting.P();
		}

	}

	@Override
	public void passThreadArguments(Object[] arguments) {
		// TODO Auto-generated method stub

	}

	/**
	 * this method don't make anything because FCFSSchedule is not-preempted
	 * scheduale
	 */
	@Override
	public void blockThread() {
		runningThread.setThreadState(THREAD_BLOCKED);
		runningThread.stopExecution();

	}

	@Override
	public void resumeThread(MiniThread thread) {

		suspendedQueue.remove(thread.getTid());
		int state = thread.getThreadState();
		switch (state) {

		case THREAD_SUSPENDED_BLOCKED:
			thread.setThreadState(THREAD_BLOCKED);
			readyQueue.append(thread);
			break;
		case THREAD_SUSPENDED_READY:
			thread.setThreadState(THREAD_READY);
			readyQueue.append(thread);
			if (runningThread == null)
				waiting.V();
		}
	}

	@Override
	public void suspendThread(MiniThread thread) {
		thread.stopExecution();
		int state = thread.getThreadState();
		switch (state) {
		case THREAD_RUNNING:
			thread.setThreadState(THREAD_SUSPENDED_READY);
			runningThread = null;
			waiting.V();
			break;
		case THREAD_BLOCKED:
			thread.setThreadState(THREAD_SUSPENDED_BLOCKED);
			runningThread = null;
			waiting.V();
			break;
		case THREAD_READY:
			readyQueue.removeThread(thread.getTid());
			thread.setThreadState(THREAD_SUSPENDED_READY);
			break;
		}
		suspendedQueue.put(thread.getTid(), thread);
	}

	@Override
	public void terminateProcess(MiniProcess process) {
		Hashtable<String, MiniThread> threads = process.getThreads();
		Enumeration<MiniThread> e = threads.elements();
		while (e.hasMoreElements()) {
			terminateThread(e.nextElement());
		}
	}

	@Override
	public void terminateThread(MiniThread thread) {

		thread.getProcess().threadTerminated(thread.getTid());
		int threadState = thread.getThreadState();
		switch (threadState) {
		case THREAD_SUSPENDED_READY:
			suspendedQueue.remove(thread.getTid());
			break;
		case THREAD_SUSPENDED_BLOCKED:
			suspendedQueue.remove(thread.getTid());
			break;
		case THREAD_BLOCKED:
			runningThread = null;
			waiting.V();
			break;
		case THREAD_RUNNING:
			runningThread = null;
			waiting.V();
		default:
			readyQueue.removeThread(thread.getTid());
			break;
		}

	}

	@Override
	public void threadTerminated() {
		runningThread = null;
		waiting.V();
	}

	/**
	 * not do any thing because this schedule not-preempted
	 */
	@Override
	public void unblockThread(MiniThread thread) {	
	
		if (runningThread == thread){
			thread.resumeExecution();// not do any thing
			thread.setThreadState(THREAD_RUNNING);		
		}
		else
		{
			thread.setThreadState(THREAD_READY);
		}
			
	}

	public void addThread(MiniThread thread) {
		super.addThread(thread);
		System.out.println("            added Thread" + thread.getName());
		if (runningThread == null)
			waiting.V();
	}

	@Override
	public void threadStopped(MiniThread thread) {
		readyQueue.append(runningThread);
		runningThread = null;
		waiting.V();
	}
	public  String getSchedulerName(){
		return "FCFS";
	}

	@Override
	public int getQuantum() {
		// TODO Auto-generated method stub
		return 0;
	}
}
